from interaction20 import Interaction20
from experimentoutput import pickOtherExperiment

# Lesson 3 Interaction Derived Class (Primitive Or Composite Type Interaction)
    # Properties for Primitive Type
       # preInteraction = None
       # enactedInteraction => (self.experiment, self.result, self.valence)

    # Properties for Composite Type
      # preInteraction = Interaction(experiment, result, '') => contextInteraction
      # postInteraction => (self.experiment, self.result,'') => enactedInteraction

class Interaction30(Interaction20):

    def __init__(self, contextInteraction, enactedInteraction):
        super().__init__(enactedInteraction.experiment, enactedInteraction.result, enactedInteraction.valence)
        self.preInteraction = contextInteraction

    def __repr__(self):
        if self.preInteraction is not None:
            return '[({},{}) , ({},{})]'.format(self.preInteraction.experiment, self.preInteraction.result, self.experiment, self.result)
        else:
            return super().__repr__()

    # Override - get Interaction Name
    def getInteractionName(self):
        interationName = (self.preInteraction.experiment + self.preInteraction.result) if self.preInteraction is not None else ''
        interationName += super().getInteractionName()
        return interationName

    #Store new Primitive Interaction
    @classmethod
    def createPrimitiveInteraction(cls, experiment, result, valence):
        key = experiment + result
        if key not in cls.dictInteraction:
            inter = Interaction30(None, Interaction20(experiment, result, valence))
            cls.dictInteraction[key] = inter

    #Store new Composite Interaction
    @classmethod
    def learnCompositeInteraction(cls, contextInteraction, enactedInteraction):
        if contextInteraction is not None and enactedInteraction is not None:
            key = contextInteraction.experiment + contextInteraction.result + enactedInteraction.experiment + enactedInteraction.result
            if key not in cls.dictInteraction:
                inter = Interaction30(contextInteraction, enactedInteraction)
                cls.dictInteraction[key] = inter
                print(' '*80, ' Learn ', inter)
            else:
                print(' '*98, ' Recollect Learning ', cls.dictInteraction[key])

    #Anticipate next Interaction
    @classmethod
    def anticipate(cls, enactedInteraction):
        dictAnticipations = {}
        if enactedInteraction is not None:
            for interactionKey in cls.dictInteraction:
                interaction = cls.dictInteraction[interactionKey]
                if interaction.preInteraction is not None:
                    if interaction.preInteraction.getInteractionName() == enactedInteraction.getInteractionName():
                        #Anticipate the postInteraction
                        key = interaction.experiment + interaction.result
                        if key not in dictAnticipations:
                            proposedAnticipation = Interaction30(None, interaction)
                            dictAnticipations[key] = proposedAnticipation
                            print(' '*55, ' Afforded ', proposedAnticipation)
        return dictAnticipations

    #Choose Next Experiment based on anticipation
    @classmethod
    def selectExperiment(cls, dictAnticipations, randomFlag = False, lastExperiment = ''):
        # Sort by decreasing valence
        listAnticipations = list(dictAnticipations.values())
        listAnticipations.sort(key=lambda x: x.valence, reverse=True)

        #expNext = ''
        #for interaction in listAnticipations:
        if len(listAnticipations)>0:
            interaction = listAnticipations[0]
            if interaction.valence >= 0:
                expNext = interaction.experiment
                print('Next Afforded Experiment: ' + expNext)
        #        break
            else:
                print(' '*55, ' Negative Afforded Valence(s)')
                expNext = pickOtherExperiment(interaction.experiment, randomFlag, False)
        #        break
        else:
            expNext = pickOtherExperiment(lastExperiment, randomFlag, False)

        return expNext